﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices; 



namespace CardCharger.lib
{

    /// <summary>
    /// 非接触CPU卡 BC750 读卡器
    /// </summary>
    public class BC750_CardReader : ICardReader
    {


        #region 底层库
        //=========================== System Function =============================
        [DllImport("hfrdapi.dll")]
        static extern int Sys_GetDeviceNum(UInt16 vid, UInt16 pid, ref UInt32 pNum);

        [DllImport("hfrdapi.dll")]
        static extern int Sys_GetHidSerialNumberStr(UInt32 deviceIndex,
                                                    UInt16 vid,
                                                    UInt16 pid,
                                                    ref Char deviceString,
                                                    UInt32 deviceStringLength);

        [DllImport("hfrdapi.dll")]
        static extern int Sys_Open(ref IntPtr device,
                                   UInt32 index,
                                   UInt16 vid,
                                   UInt16 pid);

        [DllImport("hfrdapi.dll")]
        static extern bool Sys_IsOpen(IntPtr device);

        [DllImport("hfrdapi.dll")]
        static extern int Sys_Close(ref IntPtr device);

        [DllImport("hfrdapi.dll")]
        static extern int Sys_SetLight(IntPtr device, byte color);

        [DllImport("hfrdapi.dll")]
        static extern int Sys_SetBuzzer(IntPtr device, byte msec);

        [DllImport("hfrdapi.dll")]
        static extern int Sys_SetAntenna(IntPtr device, byte mode);

        [DllImport("hfrdapi.dll")]
        static extern int Sys_InitType(IntPtr device, byte type);
        /*
            功能：设置读写器非接触工作方式 

            原型：int WINAPI Sys_InitType(HID_DEVICE device, BYTE type)

            参数： device [IN] 要操作的设备，由Sys_Open()获得

            type   [IN] 读写卡器工作方式

            返回：0       -> 操作成功

            其它    -> 见错误代码表

            说明：只支持单一协议的读写器仅对部分方式有效

            type = 'A' -> 设置为ISO14443A方式，ISO14443A类别的函数使用此方式；

            type = 'B' -> 设置为ISO14443B方式，SGIDC(二代证)、ISO14443B-4类别的函数使用此方式；

            type = 'r' -> 设置为AT88RF020卡方式，AT88RF020类别的函数使用此方式；

            type = 's' -> 设置为ST卡方式，SR176、SRI4K类别的函数使用此方式；

            type = '1' -> 设置为ISO15693方式，ISO15693类别的函数使用此方式；

         */

        //===========================       M1 卡     =============================

        //===========================      CPU 卡     =============================
        [DllImport("hfrdapi.dll")]
        //参数：device  [IN]  要操作的设备，由Sys_Open()获得
        //mode    [IN]  寻卡方式
        //pData   [OUT] 返回的数据
        //pMsgLg  [OUT] 返回数据的长度
        //返回：0       -> 操作成功
        //其它    -> 见错误代码表
        //说明：mode = 0x26 -> REQA方式，寻未进入休眠状态的卡
        //mode = 0x52 -> WUPA方式，寻所有状态的卡
        //pData：4字节CSN + 复位信息内容
        static extern int TyA_Reset(IntPtr device, byte mode, byte[] pData, ref byte pMsgLg);

        [DllImport("hfrdapi.dll")]
        //功能：向符合ISO14443A标准的CPU卡发送COS命令
        /*
        参数：device   [IN]  要操作的设备，由Sys_Open()获得

              pCommand [IN]  命令内容

              cmdLen   [IN]  命令长度

              pData    [OUT] 卡片返回的数据

              pMsgLg   [OUT] 返回数据长度

        返回：0       -> 操作成功

              其它    -> 见错误代码表
         * */
        static extern int TyA_CosCommand(IntPtr device,
            byte[] pCommand, byte cmdLen, byte[] pData, ref UInt16 pMsgLg);

        [DllImport("hfrdapi.dll")]
        //功能：令符合ISO14443A标准的CPU卡退出激活状态
        //原型：int WINAPI TyA_Deselect(HID_DEVICE device)
        //参数：device [IN] 要操作的设备，由Sys_Open()获得
        //返回：0       -> 操作成功
        //其它    -> 见错误代码表
        static extern int TyA_Deselect(IntPtr device);

        enum ErrorCode
        {

            OK = 0,
            COM = 0x0A,//通用错误
            Unsupport = 0x0B,
            Params = 0x0C,
            NoCard = 0x0D,
            Wireless = 0x0E,
            InventoryFail = 0x14,
            CardReset = 0x15,
            KeyAuthFail = 0x16,
            ReadCardFail = 0x17,
            WriteCardFail = 0x18,
            FlashAddrError = 0x21,
            FlashDataLenError = 0x22,
            ReadFlashFail = 0x23,
            WriteFlashFail = 0x24,
            EraseFlashFail = 0x25,

            HID_DEVICE_FAILED = 0xC0,//HID通信一般错误
            HID_DEVICE_NOT_FOUND = 0xC1,//没找到设备
            HID_DEVICE_NOT_OPENED = 0xC2,//设备未打开
            HID_DEVICE_ALREADY_OPENED = 0xC3,//设备已经打开
            HID_DEVICE_TRANSFER_TIMEOUT = 0xC4,//数据传输超时
            HID_DEVICE_TRANSFER_FAILED = 0xC5,//数据传输失败
            HID_DEVICE_CANNOT_GET_HID_INFO = 0xC6,//获取设备信息失败
            HID_DEVICE_HANDLE_ERROR = 0xC7,//设备句柄错误
            HID_DEVICE_INVALID_BUFFER_SIZE = 0xC8,//缓存大小错误
            HID_DEVICE_SYSTEM_CODE = 0xC9,//系统错误
            HID_DEVICE_UNKNOW_ERROR = 0xCA,//HID通信未知错误
            LIB_FAILED = 0xE0,//库函数一般错误
            LIB_CHECKDATA_FAILED = 0xE1//数据包数据有误

        }

        #endregion



        #region 接口实现
        IntPtr fd = new IntPtr(-1);
        static UInt16 d_PID = 0x8020;
        static UInt16 d_VID = 0x0416;
        public IntPtr readerFd
        {
            get
            {
                return fd;
            }
            set
            {
                fd = value;
            }
        }



        #region 读卡器操作部分
        /// <summary>
        /// 打开设备
        /// </summary>
        /// <param name="para"></param>
        /// <returns>成功：设备句柄，失败 -1</returns>
        public IntPtr CardReaderOpen(string para)
        {
            try
            {
                if (fd.ToInt32() > 0) { Sys_Close(ref fd); }
                else
                {

                    UInt16 index = 0;
                    try { index = UInt16.Parse(para.ToLower().Substring(3)); if (index > 0)index -= 1; }
                    catch { index = 0; }
                    int result = Sys_Open(ref fd, index, d_VID, d_PID);
                    switch (result)
                    {
                        case 0:
                            Sys_SetBuzzer(fd, 3);
                            return fd; //成功
                        default:
                            return new IntPtr(-1);
                    }
                }
            }
            catch { }

            return new IntPtr(-1);
        }


        /// <summary>
        /// 关闭设备
        /// </summary>
        /// <returns>成功: true ,失败:false</returns>
        public bool CardReaderClose()
        {
            if (Sys_IsOpen(fd)) { Sys_Close(ref fd); return (Sys_IsOpen(fd) ? false : true); }
            else return true;
        }


        /// <summary>
        /// 复位读卡器
        /// </summary>
        /// <param name="paras"></param>
        /// <returns>返回读卡器复位字符</returns>
        public string CardReaderReset(object paras)
        {
            return "NULL";
        }

        public string CardReaderVersion()
        {
            return "NULL";
        }


        /// <summary>
        /// 对读卡器的一般控制 
        /// </summary>
        /// <param name="para">
        /// [0] ,[1] = {"Light",["0","1","2","3"]}//灯，灭，红，绿，黄
        /// [0] ,[1] = {"Buzzer","number"}//蜂鸣器响，number *10 ms
        /// </param>
        /// <returns></returns>
        public string CardReaderCtrl(object[] para)
        {
            if (para == null || para.Length < 2) return null;
            String cmd = (String)para[0];
            String pdata = (String)para[1];
            
            switch (cmd)
            {

                case "Light":
                    {
                        byte number = byte.Parse(pdata);
                        Sys_SetLight(fd, number); return null;
                    }

                case "Buzzer":
                    {
                        byte number = byte.Parse(pdata);
                        Sys_SetBuzzer(fd, number); return null;
                    }

                case "Antenna":
                    {
                        string setstring = para[1].ToString().ToLower();
                        switch (setstring) { 
                            case "on":
                                Sys_SetAntenna(fd, 1);
                                return null;
                            case "off":
                                Sys_SetAntenna(fd, 0);
                                return null;
                            case "reset on":
                                Sys_SetAntenna(fd,0);
                                Sys_SetAntenna(fd,1);
                                return null;
                            case "reset off":
                                Sys_SetAntenna(fd,1);
                                Sys_SetAntenna(fd,0);
                                return null;
                            default:
                                return null;
                        }
                    }

                default:
                    return null;
            }
            return null;
        }

        #endregion


        #region 卡操作部分
        /// <summary>
        /// 卡复位
        /// </summary>
        /// <returns>返回卡 的复位信息</returns>
        public string CardReset()
        {

            Sys_SetAntenna(fd, 0);
            //设置天线
            int r = Sys_InitType(fd, (byte)'A');
            int rr = Sys_SetAntenna(fd, 1);



            byte[] pData = new byte[100];
            byte pMsgLg = 0;
            int result = TyA_Reset(fd, 0x52, pData, ref pMsgLg);

            if (result == 0)
            {

                //返回数据
                return Ulitily.ShareClass.hexByteArrayToString(pData, pMsgLg).Replace("-", "");

            }
            return null;
        }


        /// <summary>
        /// 读取卡的序列号
        /// </summary>
        /// <returns></returns>
        public byte[] CardGetId()
        {
            try
            {

                string reset = CardReset();
                string idstring = reset.Substring(0, 8);
                byte[] id = Ulitily.ShareClass.strToHexByteArray(idstring);
                byte[] id8 = new byte[8];
                Array.Clear(id8, 0, id8.Length);
                Array.Copy(id, 0, id8, 0, 4);
                return id8;
            }
            catch { return null; }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="len"></param>
        /// <param name="comm"></param>
        /// <param name="lenr"></param>
        /// <param name="resp"></param>
        /// <returns>正常 sw1 sw2,不正常 ffff</returns>
        public ushort CardApdu(ushort len, byte[] comm, ref ushort lenr, byte[] resp)
        {
            int result = TyA_CosCommand(fd, comm, (byte)len, resp, ref lenr);
            UInt16 ErrorCode = 0;
            if (result != 0) return 0xffff;
            else
            {

                if (lenr < 2) return 0xffff;
                ErrorCode = resp[lenr - 2];
                ErrorCode <<= 8;
                ErrorCode += resp[lenr - 1];
            }
            return ErrorCode;
        }

        public void Card_SetNAD(byte nad)
        {
            // throw new NotImplementedException();
        }

        #endregion

        #endregion


    }


}
